/**
 * 
 */
package org.statewalker.fsm.providers;

import java.util.Stack;

/**
 * This is an utility class used to build a graph of transitions. This class
 * defines transitions in an underlying {@link FsmTransitionsRegistry} instance.
 * 
 * @author kotelnikov
 * @param <S> type of state keys
 * @param <E> type of event keys
 */
public class FsmTransitionsConfigurator {

    /**
     * The registry of transitions. This class changes the configuration in this
     * registry.
     */
    private FsmTransitionsRegistry fRegistry;

    /**
     * An internal stack used to keep the current key of a state. Transitions
     * are defined for the currently active state.
     */
    private Stack<String> fStack = new Stack<String>();

    /**
     * The default constructor. It saves the given registry to configure in an
     * internal field.
     * 
     * @param registry the registry to configure
     */
    public FsmTransitionsConfigurator(FsmTransitionsRegistry registry) {
        fRegistry = registry;
    }

    /**
     * This method is called for a new state for which transitions should be
     * defined.
     * 
     * @param state the state to initialize
     */
    public void beginState(String state) {
        fStack.push(state);
    }

    /**
     * This method is called when all transitions for the current state are
     * already defined.
     */
    public void endState() {
        fStack.pop();
    }

    /**
     * Returns the internal transition registry
     * 
     * @return the internal transition registry
     */
    public FsmTransitionsRegistry getRegistry() {
        return fRegistry;
    }

    /**
     * Marks the specified state as a "leaf" state (which does not have
     * sub-states).
     * 
     * @param state the state to mark
     */
    public void markAsLeaf(String state) {
        fRegistry.setLeafState(state);
    }

    /**
     * This method is used to define a default transition for the currently
     * active parent state. This method calls the
     * {@link IFsmMutableTransitionsRegistry#addDefaultTransition(Object, Object, Object)}
     * method.
     * 
     * @param event the event initializing the default transition.
     * @param to the target state
     */
    public void onDefaultTransition(String event, String to) {
        if (event == null)
            event = FsmBase.ANY_EVENT_KEY;
        if (to == null)
            to = FsmBase.FINAL;
        String parent = fStack.peek();
        fRegistry.addDefaultTransition(parent, event, to);
    }

    /**
     * This method notifies about a new property associated with the current
     * state.
     * 
     * @param name the name of the property
     * @param value the property value
     */
    public void onStateProperty(String name, String value) {
        String state = fStack.peek();
        fRegistry.addStateProperty(state, name, value);
    }

    /**
     * This method is used to define a transition between the specified states
     * for the given event. This method calls the
     * {@link IFsmMutableTransitionsRegistry#addTransition(Object, Object, Object, Object)}
     * method.
     * 
     * @param from the initial state of transition
     * @param event the event initializing the transition
     * @param to the target transition state
     */
    public void onTransition(String from, String event, String to) {
        if (from == null)
            from = FsmBase.INITIAL;
        if (event == null)
            event = FsmBase.ANY_EVENT_KEY;
        if (to == null)
            to = FsmBase.FINAL;
        String parent = fStack.peek();
        fRegistry.addTransition(parent, from, event, to);
    }

}